package controller

import (
	"fmt"

	"github.com/itstonight/ziyue/db"

	"github.com/gin-gonic/gin"
	"github.com/itstonight/ziyue/controller/auth"
	"github.com/itstonight/ziyue/controller/rsp"
	"github.com/itstonight/ziyue/models"
)

// DocumentQueryParams 文档查询参数
type DocumentQueryParams struct {
	Step       *int  `form:"step"`        // 使用指针允许参数为空
	UserID     *uint `form:"user_id"`     // 用户ID
	InProgress *bool `form:"in_progress"` // 是否只获取进行中的文档
}

// GetDocument 获取文档详情
func GetDocument(c *gin.Context) {
	id := c.Param("id")
	var document models.Document

	if err := db.Client.Preload("LockedUser").First(&document, id).Error; err != nil {
		rsp.Fail(c, fmt.Errorf("文档不存在：%v", err))
		return
	}

	// 根据当前校对步骤返回对应的内容
	var content string
	switch document.Step {
	case 0:
		content = document.Origin
	case 1:
		content = document.FirstCheck
	case 2:
		content = document.SecondCheck
	case 3:
		content = document.ThirdCheck
	}

	response := gin.H{
		"id":               document.ID,
		"title":            document.Title,
		"content":          content,
		"step":             document.Step,
		"process":          document.Process,
		"is_lock":          document.IsLock,
		"locked_user_name": "",
	}

	// 如果文档被锁定且有锁定用户，添加锁定用户名
	if document.IsLock && document.LockedUser != nil {
		response["locked_user_name"] = document.LockedUser.Username
	}

	rsp.Success(c, response)
}

// LockDocument 锁定文档
func LockDocument(c *gin.Context) {
	id := c.Param("id")
	user := auth.MustGetUser(c) // 使用 auth 包中的函数获取用户信息

	var document models.Document
	if err := db.Client.First(&document, id).Error; err != nil {
		rsp.Fail(c, fmt.Errorf("文档不存在：%v", err))
		return
	}

	// 检查文档是否已被锁定
	if document.IsLock && document.LockedUserID != nil && *document.LockedUserID != uint(user.ID) {
		rsp.FailWithMsg(c, "该文档已被其他用户锁定")
		return
	}

	// 使用事务来确保数据一致性
	tx := db.Client.Begin()

	// 更新锁定状态
	updates := map[string]interface{}{
		"is_lock":        true,
		"locked_user_id": user.ID,
	}

	if err := tx.Model(&document).Updates(updates).Error; err != nil {
		tx.Rollback()
		rsp.Fail(c, fmt.Errorf("锁定文档失败：%v", err))
		return
	}

	if err := tx.Commit().Error; err != nil {
		rsp.Fail(c, fmt.Errorf("提交事务失败：%v", err))
		return
	}

	rsp.Success(c, nil)
}

// UpdateDocument 更新文档
func UpdateDocument(c *gin.Context) {
	id := c.Param("id")
	userID := c.GetUint("user_id")

	var document models.Document
	if err := db.Client.First(&document, id).Error; err != nil {
		rsp.Fail(c, fmt.Errorf("文档不存在：%v", err))
		return
	}

	// 检查文档是否被当前用户锁定
	if !document.IsLock || document.LockedUserID == nil || *document.LockedUserID != userID {
		rsp.FailWithMsg(c, "您没有权限编辑此文档")
		return
	}

	// 解析请求数据
	var updateData struct {
		Content string `json:"content"`
		Step    *int   `json:"step"`
	}
	if err := c.ShouldBindJSON(&updateData); err != nil {
		rsp.FailWithMsg(c, "参数解析错误")
		return
	}

	// 更新对应步骤的内容
	switch document.Step {
	case 0:
		document.FirstCheck = updateData.Content
	case 1:
		document.SecondCheck = updateData.Content
	case 2:
		document.ThirdCheck = updateData.Content
	}

	// 如果提供了step参数，更新校对步骤
	if updateData.Step != nil {
		document.Step = *updateData.Step
		// 如果完成校对，解除锁定
		if document.Step > 0 {
			document.IsLock = false
			document.LockedUserID = nil
		}
	}

	if err := db.Client.Save(&document).Error; err != nil {
		rsp.Fail(c, fmt.Errorf("更新文档失败：%v", err))
		return
	}

	rsp.Success(c, nil)
}

func ListDocuments(c *gin.Context) {
	var params DocumentQueryParams
	if err := c.ShouldBindQuery(&params); err != nil {
		rsp.FailWithMsg(c, "参数解析错误")
		return
	}

	query := db.Client.Preload("LockedUser")

	if params.Step != nil {
		query = query.Where("step = ?", *params.Step)
	}

	// 如果指定了用户ID，只获取该用户锁定的文档
	if params.UserID != nil {
		query = query.Where("locked_user_id = ?", *params.UserID)
	}

	// 如果指定了只获取进行中的文档，添加锁定条件
	if params.InProgress != nil && *params.InProgress {
		query = query.Where("is_lock = ?", true)
	}

	var documents []models.Document
	if err := query.Find(&documents).Error; err != nil {
		rsp.Fail(c, fmt.Errorf("查询错误：%v", err))
		return
	}

	rsp.Success(c, rsp.DocumentsToResponse(documents))
}
